package com.zbkj.admin.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.collect.Lists;
import com.zbkj.admin.service.AdminEstimateAiHandleService;
import com.zbkj.admin.service.AdminProjectHandleV2Service;
import com.zbkj.common.config.BaseConfig;
import com.zbkj.common.constants.Constants;
import com.zbkj.common.constants.RedisKeyConstants;
import com.zbkj.common.enums.InformationTypEnum;
import com.zbkj.common.enums.ProjectTypeEnum;
import com.zbkj.common.exception.CommonException;
import com.zbkj.common.exception.ExceptionCodeEnum;
import com.zbkj.common.model.project.EstimateAi;
import com.zbkj.common.model.project.EstimateInformation;
import com.zbkj.common.model.project.ProjectInfo;
import com.zbkj.common.model.project.ProjectInformation;
import com.zbkj.common.oss.OssClientUtil;
import com.zbkj.common.request.project.AiEstimateRequest;
import com.zbkj.common.request.project.AiNotifyRequest;
import com.zbkj.common.request.project.EstimateFunToAiRequest;
import com.zbkj.common.utils.*;
import com.zbkj.common.vo.project.AiNotifyFunExcelParseVo;
import com.zbkj.service.service.project.EstimateInformationService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Auther:
 * @Date: 2024/7/15 14:14
 * @Description:
 */
@Slf4j
@Service
public class AdminEstimateAiHandleServiceImpl implements AdminEstimateAiHandleService {

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    @Lazy
    private AdminProjectHandleV2Service adminProjectHandleV2Service;
    @Autowired
    private EstimateInformationService estimateInformationService;
    @Autowired
    private RestTemplateUtil restTemplateUtil;
    @Autowired
    private OssClientUtil ossClientUtil;
    @Autowired
    private BaseConfig baseConfig;

    @Value("${ai.estimateReqUrl:}")
    private  String estimateReqUrl;

    @Value("${ai.estimateFunReqUrl:}")
    private String estimateFunReqUrl;

    public void estimateAiReqParamBuild(int sourceType, AiEstimateRequest aiRequest, ProjectInfo projectInfo, List<EstimateAi> estimateAiList, List<ProjectInformation> informationList) {
        aiRequest.setType(1);
        aiRequest.setProjectId(projectInfo.getId());
        aiRequest.setProjectName(projectInfo.getProjectName());
        aiRequest.setProjectType(projectInfo.getProjectType());
        aiRequest.setSourceType(sourceType);
        if(ProjectTypeEnum.isType2(projectInfo.getProjectType())) {
            //军标获取重用程度
            aiRequest.setReuseItem(projectInfo.getReuseItem());
        }
        if(sourceType == 2) {
            this.qiContentReqParamBuild(aiRequest,estimateAiList);
        } else if(sourceType == 1) {
            this.aiFileReqParamBuild(aiRequest, informationList);
        }
        //log.info("ai估算请求-para:{}",JSON.toJSONString(aiRequest));
    }

    @Override
    public void estimateStartAiRequest(AiEstimateRequest aiRequest) {
        JSONObject resutl = null;
        aiRequest.setType(1);
        String reqStr =  JSON.toJSONString(aiRequest);
        try {
            JSONObject reqParam = JSON.parseObject(reqStr);
            resutl = restTemplateUtil.postJsonDataAndReturnJson(estimateReqUrl,reqParam);
            if(Objects.nonNull(resutl) && resutl.containsKey("code") && resutl.getIntValue("code") == 200) {
            } else  {
                if(Objects.isNull(resutl)) {
                    throw new CommonException("调用AI接口返回值为空");
                }
                throw new CommonException("调用AI接口返回错误:"+resutl.getString("message"));
            }
        } catch (CommonException ce) {
            log.error("estimateStartAiRequest-param:{}-error:",reqStr,ce.getMessage());
        }catch (Exception e) {
            log.error("estimateStartAiRequest-param:{}-error:",reqStr,e);
            throw new CommonException("估算调用AI接口请求异常");
        }finally {
            log.info("估算调用AI调用-estimateStartAiRequest-param:{}-result:{}",reqStr,resutl);
        }
    }

    @Override
    public void estimateStopAiRequest(Long projectId) {
        JSONObject resutl = null;
        try {
            if(Objects.isNull(projectId) || projectId.longValue() <=0) {
                return;
            }
            AiEstimateRequest aiRequest = new AiEstimateRequest();
            aiRequest.setProjectId(projectId);
            aiRequest.setType(2);
            JSONObject reqParam = JSON.parseObject(JSON.toJSONString(aiRequest));
            resutl = restTemplateUtil.postJsonDataAndReturnJson(estimateReqUrl,reqParam);
        } catch (Exception e) {
            log.error("estimateStopAiRequest-projectId:{}-error:",projectId,e);
        }finally {
            log.info("estimateStopAiRequest-projectId:{}-result:{}",projectId,resutl);
        }
    }


    @Override
    public void estimateAiNotify(AiNotifyRequest notifyRequest, HttpServletRequest request) {
        String errorMsg = null;
        ProjectInfo projectInfo;
        try {
            //检查请求IP是否配置白名单
            this.notifyIpCheck(request);
            projectInfo = adminProjectHandleV2Service.getProjectAndCheck(notifyRequest.getProjectId());
            try {
                if(!projectInfo.getAireqNo().equals(notifyRequest.getReqNo())) {
                    throw new CommonException("估算流水号已变更,回调结果不处理");
                }
                //检查AI回调通知-是否已处理
                int rowNum = estimateInformationService.getAiInformationCount(notifyRequest.getProjectId(),InformationTypEnum.TYPE41.getType(),notifyRequest.getReqNo());
                if(rowNum > 0) {
                    throw new CommonException("估算流水号回调结果已处理");
                }
            } catch (CommonException ce) {
                //项目不存在 | 项目已撤回  直接返回成功
                errorMsg = ce.getMessage();
                return;
            }
            if(Objects.nonNull(notifyRequest.getCode()) && notifyRequest.getCode() !=0) {
                //ai估算-返回退款处理
                adminProjectHandleV2Service.projectFefundHandle(projectInfo);
                return;
            }

            String fileName = FilenameUtils.getName(notifyRequest.getFilePath());
            String fileType = fileName.substring(fileName.lastIndexOf("."));
            if(!CommonUtil.fileTypeCheck(Constants.EXCLE_FILE_TYPES, fileType)) {
                throw new CommonException("估算结果文件不为excel类型文件");
            }
            //解析ai估算结果文件获取功能点明细集合
            List<AiNotifyFunExcelParseVo> parseFunDataList = aiNotifyFileParse(notifyRequest);
            //如果解析文件明细为空不抛出异常-正常处理
            /*if(CollectionUtils.isEmpty(parseFunDataList)) {
                throw new CommonException("结果文件解析数据为空");
            }*/
            //ai估算回调通知保存处理
            adminProjectHandleV2Service.aiNotifyResultSaveHandle(notifyRequest,projectInfo,parseFunDataList);
        } catch (CommonException ce) {
            errorMsg = ce.getMessage();
            throw ce;
        } catch (Exception e) {
            errorMsg = "结算AI通知处理失败";
            log.error("estimateAiNotify-param:{}-error:",JSON.toJSONString(notifyRequest),e);
            throw new CommonException(errorMsg);
        }finally {
            log.info("估算调用AI通知-estimateAiNotify--param:{}-result:{}", JSON.toJSONString(notifyRequest),errorMsg);
        }
    }

    @Override
    public void notifyIpCheck(HttpServletRequest request) {
        /*String reqIp = CommonUtil.getClientIp(request);
        log.info("notifyIpCheck--reqIp:{}",reqIp);
        if (StringUtils.isBlank(reqIp) || !redisUtil.hashExists(RedisKeyConstants.AI_REQUEST_IPWHITE, reqIp)) {
            throw new CommonException(ExceptionCodeEnum.AUTHO_IP_ERROR.getMessage());
        }*/
    }

    /**
     * 组装ai请求需求拆分内容对象
     * @param aiRequest
     * @param estimateList
     */
    private void qiContentReqParamBuild(AiEstimateRequest aiRequest, List<EstimateAi> estimateList) {
        Map<String,List<EstimateAi>> titleGroupMap = estimateList.stream().collect(Collectors.groupingBy(k->k.getTitle()));
        Map<String,Integer> titlSortMap = estimateList.stream().collect(Collectors.toMap(k->k.getTitle(),v->v.getTitleSort(),(ov,nv)->ov));
        List<AiEstimateRequest.AiTileRequest> tileReqList = Lists.newArrayList();
        titlSortMap.forEach((key,val)->{
            AiEstimateRequest.AiTileRequest titleReq = new AiEstimateRequest.AiTileRequest();
            titleReq.setTitle(key);
            titleReq.setTitleNum(val);
            List<EstimateAi> tempList = titleGroupMap.getOrDefault(key,Lists.newArrayList());
            titleReq.setSubsysName(tempList.size()>0 ? tempList.get(0).getSubsysName() : "");
            List<AiEstimateRequest.AiContentRequest> contentReqList = Lists.newArrayList();
            for(EstimateAi ai : tempList) {
                AiEstimateRequest.AiContentRequest aiContentReq = new AiEstimateRequest.AiContentRequest();
                aiContentReq.setContent(ai.getContent());
                aiContentReq.setSortNum(ai.getSortNum());
                contentReqList.add(aiContentReq);
            }
            //titleReq.setContentList(contentReqList.stream().sorted(Comparator.comparing(c->c.getSortNum())).collect(Collectors.toList()));
            titleReq.setContentList(contentReqList);
            tileReqList.add(titleReq);
        });
        //aiRequest.setContentList(tileReqList.stream().sorted(Comparator.comparing(t->t.getTitleNum())).collect(Collectors.toList()));
        aiRequest.setContentList(tileReqList);
    }

    private void aiFileReqParamBuild(AiEstimateRequest aiRequest, List<ProjectInformation> informationList) {
        List<AiEstimateRequest.FileContent> fileList = Lists.newArrayList();
        for(ProjectInformation information : informationList) {
            AiEstimateRequest.FileContent fileContent = new AiEstimateRequest.FileContent();
            fileContent.setFileName(FileUtil.subFileName(information.getFileName()));
            fileContent.setFileUrl(ossClientUtil.addDomain(information.getFilePath()));
            fileContent.setSortNum(information.getSortNum());
            fileList.add(fileContent);
        }
        aiRequest.setFileList(fileList);
    }

    @Override
    public List<AiNotifyFunExcelParseVo> aiNotifyFileParse(AiNotifyRequest notifyParam) {
        try {
            String netFilePath = ossClientUtil.clearDomain(notifyParam.getFilePath());
            netFilePath = ossClientUtil.addInnerDomain(netFilePath);
            String fileType = netFilePath.substring(netFilePath.lastIndexOf("."));
            String tmepFilePath = baseConfig.getLocalTempFilePath(Constants.PROJECT_DOC_PREFIX,fileType);
            File outTempFile = new File(tmepFilePath);
            FileUtil.downNetFileToFile(netFilePath,outTempFile);

            final List<AiNotifyFunExcelParseVo> parseDateList = ListUtils.newArrayListWithExpectedSize(500);
            EasyExcel.read(outTempFile, AiNotifyFunExcelParseVo.class, new ReadListener<AiNotifyFunExcelParseVo>() {
                @Override
                public void invoke(AiNotifyFunExcelParseVo aiNotifyFunExcelParseVo, AnalysisContext analysisContext) {
                    parseDateList.add(aiNotifyFunExcelParseVo);
                }
                @Override
                public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                    log.info("估算通知结果文件解析-projectId:{}-reqNo:{}-filePath:{}-size:{}",notifyParam.getProjectId(),notifyParam.getReqNo(),notifyParam.getFilePath(),parseDateList.size());
                }
            }).headRowNumber(3).sheet(0).doRead();
            return parseDateList;
        } catch (CommonException ce) {
            throw ce;
        } catch (Exception e) {
            throw new CommonException("估算结果文件解析失败");
        }
    }

    @Override
    public void estimateFunToAiCall(EstimateFunToAiRequest aiRequest) {
        JSONObject resutl = null;
        String reqStr =  JSON.toJSONString(aiRequest);
        try {
            if(StringUtils.isBlank(estimateFunReqUrl)) {
                throw new CommonException("估算功能回传ai请求地址未配置");
            }
            JSONObject reqParam = JSON.parseObject(reqStr);
            resutl = restTemplateUtil.postJsonDataAndReturnJson(estimateFunReqUrl,reqParam);
            if(Objects.nonNull(resutl) && resutl.containsKey("code") && resutl.getIntValue("code") == 200) {
            } else  {
                if(Objects.isNull(resutl)) {
                    throw new CommonException("估算功能明细回传AI接口返回值为空");
                }
                throw new CommonException("估算功能明细回传AI接口返回错误:"+resutl.getString("message"));
            }
        } catch (CommonException ce) {
            log.error("estimateFunToAiCall-param:{}-error:",reqStr,ce.getMessage());
        }catch (Exception e) {
            log.error("estimateFunToAiCall-param:{}-error:",reqStr,e);
            throw new CommonException("估算功能明细回传AI接口请求异常");
        }finally {
            log.info("估算功能明细回传AI调用-estimateFunToAiCall-param:{}-result:{}",reqStr,resutl);
        }
    }
}
